#pragma once

#include <iostream>
#include <string>
#include <cstring>

using namespace std;

#define SEP " "
#define SEP_LEN strlen(SEP)
#define LINE_SEP "\r\n"
#define LINE_SEP_LEN strlen(LINE_SEP)

enum
{
    OK = 0,
    DIV_ZERO,
    MOD_ZERO,
    OP_ERROR
};

// "x op y" -> "content_len"\r\n"x op y"\r\n
// "exitcode result" -> "content_len"\r\n"exitcode result"\r\n
string enLength(const string &text)
{
    string send_string = to_string(text.size());

    send_string += LINE_SEP;
    send_string += text;
    send_string += LINE_SEP;

    return send_string;
}

// "content_len"\r\n"exitcode result"\r\n
bool deLength(const string &package, string *text)
{
    auto pos = package.find(LINE_SEP);
    if (pos == string::npos)
        return false;
    string text_len_string = package.substr(0, pos);
    int text_len = stoi(text_len_string);

    *text = package.substr(pos + LINE_SEP_LEN, text_len);

    return true;
}

class Request
{
public:
    Request(int x = 0, int y = 0, char op = 0)
        : _x(x), _y(y), _op(op)
    {
    }

    bool serialize(string *out)
    {
        *out = "";

        // 结构化 -> "x op y";
        string x_string = to_string(_x);
        string y_string = to_string(_y);

        *out += x_string;
        *out += SEP;
        *out += _op;
        *out += SEP;
        *out += y_string;

        return true;
    }

    // "x op yyyy";
    bool deserialize(const string &in)
    {
        // "x op y" -> 结构化
        auto left = in.find(SEP);
        auto right = in.rfind(SEP);

        if (left == string::npos || right == string::npos)
            return false;
        if (left == right)
            return false;
        if (right - (left + SEP_LEN) != 1)
            return false;

        string x_string = in.substr(0, left);
        string y_string = in.substr(right + SEP_LEN);

        if (x_string.empty())
            return false;
        if (y_string.empty())
            return false;

        _x = stoi(x_string);
        _y = stoi(y_string);
        _op = in[left + SEP_LEN];

        return true;
    }
    ~Request()
    {
    }

private:
    int _x;
    int _y;
    char _op;
};

class Response
{
public:
    Response(int exitcode = 0, int result = 0)
        : _exitcode(exitcode), _result(result)
    {
    }

    bool serialize(string *out)
    {
        *out = "";

        string ec_string = to_string(_exitcode);
        string res_string = to_string(_result);

        *out += ec_string;
        *out += SEP;
        *out += res_string;

        return true;
    }

    bool deserialize(const string &in)
    {
        // "exitcode result"
        auto mid = in.find(SEP);
        if (mid == string::npos)
            return false;
        string ec_string = in.substr(0, mid);
        string res_string = in.substr(mid + SEP_LEN);

        if (ec_string.empty())
            return false;
        if (res_string.empty())
            return false;

        _exitcode = stoi(ec_string);
        _result = stoi(res_string);

        return true;
    }

    ~Response()
    {
    }

private:
    int _exitcode;
    int _result;
};